/*
 * sniffer.h
 *
 *  Created on: 05/06/2011
 *      Author: George Ferreira
 */

#ifndef SNIFFER_H_
#define SCANNER_H_

#include <string>
#include <pcap.h>
#include "config.h"
#include "processor.h"
#include "types.h"

using namespace std;

class Scanner {

	public:
//		If you want send any information to processor function, use it.
		u_char userparam;

//		Sniffer session descriptor (not a really descriptor like a UNIX file descriptor :D )
		pcap 			*session;

//		Compiled program from filter string
		bpf_program_t 	program;

//		Network mask (Duhhhh)
		bpf_u_int32 	netmask;

//		Configuration object, holds execution configuration, user input has more priority than file configuration definitions
		Config 			*config;

//		String filter to compile
		const char *filter;

//		Libpcap needs a string with, at minimum, PCAP_ERRBUF_SIZE bytes to tell us some information about errors e warnings
		char errbuf[PCAP_ERRBUF_SIZE];

//		Chose compile either optimized filters or not
		int optmimize;

//		Just some stuck for testing :D
		static int nm;

		Scanner(Config *config){

//			Set up default values to our variable
			this->config 	= config;
			this->filter 	= config->filter.c_str();
			this->session 	= NULL;

			this->optmimize = 1;
			this->netmask 	= 0;
			this->userparam = 0;
		}

//		Lets the Rage of Sniffer Drive your Network Interface!!!! (like God Of War :D)
		int scan(){
			int res_loop = 1;
			if ( this->openSource() ){
				this->setFilter();
				res_loop = pcap_loop(this->session, -1, Processor::processor, &this->userparam);
			}

			return res_loop;
		}

//		Open source of data (either network card or dump file)
		int openSource(){

			// use network interface as packet source
			if ( this->config->sourceType == INTERFACE )
			{

				this->session = pcap_open_live(this->config->source.c_str(), this->config->snapeLen, this->config->promiscuous, this->config->timeToWait, errbuf);

			// use tcpdup or wireshar file as source
			}else if ( this->config->sourceType == FILESOURCE ){

				this->session = pcap_open_offline(this->config->source.c_str(), errbuf);

			}

			if ( this->session == NULL ){
				cout << "Erro ao tentar abrir a fonte de tráfego " << this->config->source << ": " << errbuf << endl;
				return 0;
			}

			return 1;
		}

//		Defines our traffic filter
		int setFilter(){
			int filterSet = 1;
			if ( this->compile(this->filter) ){
				filterSet = pcap_setfilter(this->session, &this->program);
			}

			if ( filterSet == -1 ){
				cout << "Não foi possível definir o filtro \"" << this->filter << "\":" << pcap_geterr(this->session);
				return 0;
			}

			return 1;
		}

//		Compile filter stored in this->filter
		int compile(const char *filter){
			if ( !this->session ){
				cout << "Sessão inválida" << endl;
				return 0;
			}

			if ( !this->filter ){
				cout << "Filtro inválido" << endl;
				return 0;
			}

			if ( !this->netmask ){
//				cout << "Máscara de rede inválida" << endl;
				return 0;
			}


			int comp =  pcap_compile(this->session, &this->program, this->filter, this->optmimize, this->netmask);

			if ( comp == -1 ){
				cout << "Erro ao compilar o filtro \"" << this->filter << "\": " << pcap_geterr(this->session)  << endl;
				return 0;
			}

			return 1;
		}


	private:

};

#endif /* SCANNER_H_ */
